package com.zw.cloud.tools.service;

import com.alibaba.dashscope.aigc.generation.Generation;
import com.alibaba.dashscope.aigc.generation.GenerationResult;
import com.alibaba.dashscope.aigc.generation.models.QwenParam;
import com.alibaba.dashscope.common.Message;
import com.alibaba.dashscope.common.MessageManager;
import com.alibaba.dashscope.common.Role;
import com.alibaba.dashscope.utils.Constants;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import reactor.util.function.Tuple3;
import reactor.util.function.Tuples;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Slf4j
public class AliyunTalkService {

    /**
     * https://help.aliyun.com/zh/dashscope/developer-reference/api-details?spm=a2c4g.11186623.0.0.4a78566fdb53MR
     */
    static {
        Constants.apiKey = "sk-5952a65427ff4dbfb5126d9217bc70bb";
    }

    LoadingCache<String, Tuple3<Boolean, MessageManager, QwenParam>> managerCache = CacheBuilder.newBuilder().
            // 设置并发级别为cpu核心数
                    concurrencyLevel(Runtime.getRuntime().availableProcessors()).
            expireAfterWrite(4, TimeUnit.HOURS).
            expireAfterAccess(4, TimeUnit.HOURS).
            maximumSize(100).
            build(new CacheLoader<String, Tuple3<Boolean, MessageManager, QwenParam>>() {
                @Override
                public Tuple3<Boolean, MessageManager, QwenParam> load(String userId) {
                    // 结果返回为空 会抛出InvalidCacheLoadException,后续查询会继续查询数据库,只有缓存中有值才会走缓存
                    return getMessageManager(userId);
                }
            });

    public String talk(String userId, String query) throws Exception {
        Tuple3<Boolean, MessageManager, QwenParam> tuple3 = managerCache.get(userId);
        Boolean isNew = tuple3.getT1();
        MessageManager msgManager = tuple3.getT2();
        QwenParam param = tuple3.getT3();
        if (isNew) {
            Message systemMsg = Message.builder().role(Role.SYSTEM.getValue()).content("你是智能助手机器人").build();
            msgManager.add(systemMsg);
        }
        Message userMsg = Message.builder().role(Role.USER.getValue()).content(query).build();
        msgManager.add(userMsg);
        param.setMessages(msgManager.get());

        try {
            Generation gen = new Generation();
            GenerationResult result = gen.call(param);

            msgManager.add(result);
            managerCache.put(userId, Tuples.of(true, msgManager, param));

            log.info("[AliyunTalkService][talk]userId is {},result is {}", userId, result);
            return buildGenerationResult(result);
        } catch (Exception e) {
            log.error("[AliyunTalkService][talk]userId is {},query is {},error is ", userId, query, e);
            managerCache.invalidate(userId);
            throw e;
        }
    }

    private String buildGenerationResult(GenerationResult result) {
        return result.getOutput().getChoices().stream().map(choice -> {
            Message message = choice.getMessage();
            if (Objects.isNull(message)) {
                return null;
            }
            return message.getContent();
        }).filter(Objects::nonNull).collect(Collectors.joining(" \n "));
    }

    private Tuple3<Boolean, MessageManager, QwenParam> getMessageManager(String userId) {
        log.info("[AliyunTalkService][talk]userId is {},getMessageManager not use cache", userId);
        MessageManager messageManager = new MessageManager(10);
        QwenParam qwenParam = QwenParam.builder().model(Generation.Models.QWEN_PLUS)
                .resultFormat(QwenParam.ResultFormat.MESSAGE)
                .topP(0.8)
                .enableSearch(true)
                .build();
        return Tuples.of(false, messageManager, qwenParam);
    }
}
